<template>
  <div :class="{ 'full-screen': visible }">
    <graph-config-container :graph="graph" @full="handleFull" />
    <div id="container">
      <div id="stencil"></div>
      <div id="graph-container" ref="graphRef"></div>
      <div v-show="configVisibe" id="config-container" :style="{ width: configWidth + 'px' }">
        <div class="resize-bar" @mousedown="startResize"></div>
        <node-config-container v-show="isNode" :node="curNode" @updateData="handleNode" />
        <edge-config-container v-show="!isNode" :edge="curEdge" @updateData="handleEdge" />
        <span class="iconfont collpase-icon" @click="handleCollpaseConfig"></span>
      </div>
      <span v-show="!configVisibe" class="iconfont open-icon" @click="handleOpenConfig"></span>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted, nextTick } from 'vue';
import { Graph, Shape } from '@antv/x6';
import { Stencil } from '@antv/x6-plugin-stencil';
import { Selection } from '@antv/x6-plugin-selection';
import { Keyboard } from '@antv/x6-plugin-keyboard';
import GraphConfigContainer from './components/GraphConfigContainer.vue';
import NodeConfigContainer from './components/NodeConfigContainer.vue';
import EdgeConfigContainer from './components/EdgeConfigContainer.vue';

// 响应式状态
const visible = ref(true);
const graph = ref(null);
const stencil = ref(null);
const ports = ref(null);
const curNode = ref({});
const curEdge = ref({});
const configVisibe = ref(true);
const isNode = ref(true);
const graphRef = ref(null);
const configWidth = ref(400);

// 是否全屏
const handleFull = (value) => {
  visible.value = value;
};

// 模拟接口：根据产线 ID 获取 JSON
const mockFetchJsonByLineId = async (lineId) => {
  if (lineId === 'lineA') {
    return {
      nodes: [
        {
          id: 'e2e48244-9bf6-422f-9efa-eb47cc9ef073',
          shape: 'custom-rect',
          x: 210,
          y: 160,
          width: 80,
          height: 36,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '过程' },
            rect: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refWidth: '100%', refHeight: '100%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' },
          },
        },
        {
          id: '28a055e5-61ef-4b38-a617-0c8cd2c29e73',
          shape: 'custom-polygon',
          x: 540,
          y: 200,
          width: 80,
          height: 38,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '决策' },
            polygon: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', refPoints: '0,10 10,0 20,10 10,20' },
          },
        },
        {
          id: '7f4592dd-c043-4c76-b8a5-2a43e81b6e4b',
          shape: 'custom-circle',
          x: 380,
          y: 240,
          width: 48,
          height: 48,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '连接' },
            circle: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refCx: '50%', refCy: '50%', refR: '50%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' },
          },
        },
        {
          id: '85d64897-6fa8-43d3-9516-a4b7cd4267ff',
          shape: 'custom-rect',
          x: 540,
          y: 80,
          width: 80,
          height: 36,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '结束' },
            rect: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refWidth: '100%', refHeight: '100%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', rx: 18, ry: 26 },
          },
        },
        {
          id: '909dbf00-3375-4302-82c0-4439ba09a8de',
          shape: 'custom-rect',
          x: 210,
          y: 30,
          width: 80,
          height: 36,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '开始' },
            rect: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refWidth: '100%', refHeight: '100%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', rx: 18, ry: 26 },
          },
        },
      ],
      edges: [
        {
          id: '069d99eb-d69f-4707-ab9b-f5c16d183860',
          source: { cell: 'e2e48244-9bf6-422f-9efa-eb47cc9ef073', port: '96a5fea0-ed32-43ec-908d-846da1ba0024' },
          target: { cell: '7f4592dd-c043-4c76-b8a5-2a43e81b6e4b', port: 'c51f55e3-1fc5-4434-85f2-54595b6fd7b9' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
        {
          id: '668f15c5-6f72-489a-91c3-3b4579918267',
          source: { cell: '7f4592dd-c043-4c76-b8a5-2a43e81b6e4b', port: '41014915-9be2-4bc5-b6e7-dda18473abdc' },
          target: { cell: '28a055e5-61ef-4b38-a617-0c8cd2c29e73', port: '7b7a9ac6-0a7a-4d69-9314-62a58c8da84c' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
        {
          id: 'd4ce5474-716a-4034-9345-c5f898fff499',
          source: { cell: '28a055e5-61ef-4b38-a617-0c8cd2c29e73', port: '73be868d-ddad-4b80-892e-9e538d1d05ff' },
          target: { cell: '85d64897-6fa8-43d3-9516-a4b7cd4267ff', port: 'd1374a42-9ef1-4a1b-9082-18c9f0867fe2' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
        {
          id: 'd7efd9c8-e2f7-41eb-839d-6640bedfc740',
          source: { cell: '909dbf00-3375-4302-82c0-4439ba09a8de', port: 'd1374a42-9ef1-4a1b-9082-18c9f0867fe2' },
          target: { cell: 'e2e48244-9bf6-422f-9efa-eb47cc9ef073', port: '6a7921d1-2508-45b3-97f6-16ee25e1b673' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
      ],
      attribute: {
        factoryName: '示例工厂A',
        lineName: '产线A',
        productName: '产品C',
        isLatest: '是',
        type: '生产2',
        code: 'P-001',
        name: '工单名称测试',
        jph: '100',
        version: 'v1.2',
      },
    };
  } else if (lineId === 'lineB') {
    return {
      nodes: [
        {
          id: 'node-b1',
          shape: 'custom-rect',
          x: 100,
          y: 100,
          width: 80,
          height: 36,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '开始' },
            rect: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refWidth: '100%', refHeight: '100%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', rx: 18, ry: 26 },
          },
        },
        {
          id: 'node-b2',
          shape: 'custom-polygon',
          x: 300,
          y: 150,
          width: 80,
          height: 38,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '数据' },
            polygon: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', refPoints: '10,0 40,0 30,20 0,20' },
          },
        },
        {
          id: 'node-b3',
          shape: 'custom-rect',
          x: 500,
          y: 100,
          width: 80,
          height: 36,
          attrs: {
            text: { fontSize: 12, fill: '#262626', refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontFamily: 'Arial, helvetica, sans-serif', text: '结束' },
            rect: { fill: '#ffffff', stroke: '#333333', strokeWidth: 2 },
            body: { refWidth: '100%', refHeight: '100%', strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF', rx: 18, ry: 26 },
          },
        },
      ],
      edges: [
        {
          id: 'edge-b1',
          source: { cell: 'node-b1', port: 'port-b1-bottom' },
          target: { cell: 'node-b2', port: 'port-b2-top' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
        {
          id: 'edge-b2',
          source: { cell: 'node-b2', port: 'port-b2-right' },
          target: { cell: 'node-b3', port: 'port-b3-left' },
          shape: 'edge',
          attrs: {
            lines: { connection: true, strokeLinejoin: 'round' },
            wrap: { strokeWidth: 10 },
            line: { stroke: '#A2B1C3', strokeWidth: 2, targetMarker: { name: 'block', width: 12, height: 8 } },
          },
        },
      ],
      attribute: {
        factoryName: '示例工厂B',
        lineName: '产线B',
        productName: '产品D',
        isLatest: '是',
        type: '生产3',
        code: 'P-002',
        name: '工单B测试',
        jph: '150',
        version: 'v1.3',
      },
    };
  }
  return {};
};

// 模拟接口：根据节点 ID 获取设备数据
const mockFetchDevices = async () => {
  return {
    // 产线 A 节点
    'e2e48244-9bf6-422f-9efa-eb47cc9ef073': [ // 过程
      { code: 'EQ-001', name: '焊接机器人', vendor: '张利民' },
      { code: 'EQ-002', name: '涂胶机', vendor: 'KUKA' },
      { code: 'EQ-003', name: '组装机', vendor: 'ABB' },
    ],
    '28a055e5-61ef-4b38-a617-0c8cd2c29e73': [ // 决策
      { code: 'EQ-006', name: '存储器', vendor: 'Intel' },
      { code: 'EQ-007', name: '数据采集器', vendor: 'Honeywell' },
      { code: 'EQ-008', name: '分析仪', vendor: 'Keysight' },
      { code: 'EQ-009', name: '服务器', vendor: 'Dell' },
      { code: 'EQ-010', name: '备份设备', vendor: 'HP' },
    ],
    '7f4592dd-c043-4c76-b8a5-2a43e81b6e4b': [ // 连接
      { code: 'EQ-004', name: '切割机', vendor: 'FANUC' },
      { code: 'EQ-005', name: '检测仪', vendor: 'Siemens' },
    ],
    '85d64897-6fa8-43d3-9516-a4b7cd4267ff': [ // 结束
      { code: 'EQ-011', name: '包装机', vendor: 'Bosch' },
    ],
    '909dbf00-3375-4302-82c0-4439ba09a8de': [ // 开始
      { code: 'EQ-012', name: '传送带', vendor: 'Mitsubishi' },
      { code: 'EQ-013', name: '分拣机', vendor: 'Omron' },
    ],
    // 产线 B 节点
    'node-b1': [ // 开始
      { code: 'EQ-014', name: '喷涂机', vendor: 'Yaskawa' },
      { code: 'EQ-015', name: '打磨机', vendor: '3M' },
    ],
    'node-b2': [ // 数据
      { code: 'EQ-016', name: '数据库服务器', vendor: 'IBM' },
      { code: 'EQ-017', name: '数据分析模块', vendor: 'SAP' },
      { code: 'EQ-018', name: '存储单元', vendor: 'Western Digital' },
      { code: 'EQ-019', name: '网络交换机', vendor: 'Cisco' },
      { code: 'EQ-020', name: '备份系统', vendor: 'NetApp' },
    ],
    'node-b3': [ // 结束
      { code: 'EQ-021', name: '物流机器人', vendor: 'Fanuc' },
    ],
  };
};

// 初始化画布
const initGraph = () => {
  graph.value = new Graph({
    container: document.getElementById('graph-container'),
    grid: true,
    mousewheel: {
      enabled: true,
      zoomAtMousePosition: true,
      modifiers: 'ctrl',
      minScale: 0.5,
      maxScale: 3,
    },
    panning: {
      enabled: true,
      modifiers: [],
      eventTypes: ['leftMouseDown', 'mouseWheel'],
    },
    connecting: {
      router: { name: 'manhattan', args: { padding: 1 } },
      connector: { name: 'rounded', args: { radius: 8 } },
      anchor: 'center',
      connectionPoint: 'anchor',
      allowBlank: false,
      snap: { radius: 20 },
      createEdge() {
        return new Shape.Edge({
          attrs: {
            line: {
              stroke: '#A2B1C3',
              strokeWidth: 2,
              targetMarker: { name: 'block', width: 12, height: 8 },
            },
          },
          zIndex: 0,
        });
      },
      validateConnection({ targetMagnet }) {
        return !!targetMagnet;
      },
    },
    highlighting: {
      magnetAdsorbed: {
        name: 'stroke',
        args: { attrs: { fill: '#5F95FF', stroke: '#5F95FF' } },
      },
    },
    resizing: true,
    rotating: true,
    selecting: {
      enabled: true,
      multiple: true,
      rubberband: true,
      showNodeSelectionBox: true,
      showEdgeSelectionBox: true,
    },
    snapline: true,
    keyboard: true,
    clipboard: true,
    history: true,
  });

  graph.value.use(
      new Selection({
        enabled: true,
        multiple: true,
        rubberband: true,
        showNodeSelectionBox: true,
        showEdgeSelectionBox: true,
      })
  );
  graph.value.use(new Keyboard({ enabled: true }));
};

// 画布绑定监听事件
const graphOnEvent = () => {
  const showPorts = (ports, show) => {
    for (let i = 0, len = ports.length; i < len; i++) ports[i].style.visibility = show ? 'visible' : 'hidden';
  };

  graph.value.on('node:mouseenter', () => showPorts(graphRef.value.querySelectorAll('.x6-port-body'), true));
  graph.value.on('node:mouseleave', () => showPorts(graphRef.value.querySelectorAll('.x6-port-body'), false));

  graph.value.on('node:added', async ({ node }) => {
    const nodeId = node.id;
    const devices = await mockFetchDevices();
    const deviceList = devices[nodeId] || [];
    const currentData = node.getData() || {};
    const initialData = {
      factoryName: '示例工厂',
      lineName: '产线',
      productName: '产品',
      isLatest: '是',
      type: '生产',
      code: 'P-001',
      name: node.label || '工单名称测试',
      jph: '100',
      version: 'v1.2',
      deviceList,
    };
    node.setData({ ...currentData, ...initialData });
    curNode.value = node;
    isNode.value = true;
    console.log(`节点 ${nodeId} 添加，设备列表:`, deviceList);
  });

  graph.value.on('node:click', async ({ node }) => {
    const nodeId = node.id;
    const devices = await mockFetchDevices();
    const deviceList = devices[nodeId] || [];
    const currentData = node.getData() || {};
    node.setData({ ...currentData, deviceList });
    curNode.value = node;
    isNode.value = true;
    console.log(`节点 ${nodeId} 点击，设备列表:`, deviceList);
  });

  graph.value.on('edge:added', ({ edge }) => {
    isNode.value = false;
    curEdge.value = edge;
  });

  graph.value.on('edge:click', ({ edge }) => {
    isNode.value = false;
    curEdge.value = edge;
  });
};

// 初始化节点数据
const initializeNodeData = async (node) => {
  const nodeId = node.id;
  const devices = await mockFetchDevices();
  const deviceList = devices[nodeId] || [];
  const initialData = {
    factoryName: '示例工厂',
    lineName: '产线',
    productName: '产品',
    isLatest: '是',
    type: '生产',
    code: 'P-001',
    name: node.label || '工单名称测试',
    jph: '100',
    version: 'v1.2',
    deviceList,
  };
  node.setData(initialData);
};

// 绑定画布快捷键
const graphBindKey = () => {
  graph.value.bindKey(['meta+c', 'ctrl+c'], () => {
    const cells = graph.value.getSelectedCells();
    if (cells.length) graph.value.copy(cells);
    return false;
  });
  graph.value.bindKey(['meta+x', 'ctrl+x'], () => {
    const cells = graph.value.getSelectedCells();
    if (cells.length) graph.value.cut(cells);
    return false;
  });
  graph.value.bindKey(['meta+v', 'ctrl+v'], () => {
    if (!graph.value.isClipboardEmpty()) {
      const cells = graph.value.paste({ offset: 32 });
      graph.value.cleanSelection();
      graph.value.select(cells);
    }
    return false;
  });
  graph.value.bindKey(['meta+z', 'ctrl+z'], () => {
    if (graph.value.history.canUndo()) graph.value.history.undo();
    return false;
  });
  graph.value.bindKey(['meta+shift+z', 'ctrl+shift+z'], () => {
    if (graph.value.history.canRedo()) graph.value.history.redo();
    return false;
  });
  graph.value.bindKey(['meta+a', 'ctrl+a'], () => {
    const nodes = graph.value.getNodes();
    if (nodes) graph.value.select(nodes);
  });
  graph.value.bindKey('backspace', () => {
    const cells = graph.value.getSelectedCells();
    if (cells.length) graph.value.removeCells(cells);
  });
  graph.value.bindKey(['ctrl+1', 'meta+1'], () => {
    if (graph.value.zoom() < 1.5) graph.value.zoom(0.1);
  });
  graph.value.bindKey(['ctrl+2', 'meta+2'], () => {
    if (graph.value.zoom() > 0.5) graph.value.zoom(-0.1);
  });
};

// 初始化左侧流程控件面板
const initStencil = async () => {
  stencil.value = new Stencil({
    title: '流程图',
    target: graph.value,
    stencilGraphWidth: 250,
    stencilGraphHeight: 320,
    collapsable: true,
    notFoundText: '暂未匹配到结果',
    search: (cell, keyword) => {
      if (keyword) {
        return cell.label.includes(keyword);
      }
      return true;
    },
    groups: [
      { title: '基础节点', name: 'group1' },
      { title: '图片节点', name: 'group2', graphHeight: 250, layoutOptions: { rowHeight: 70 } },
    ],
    layoutOptions: {
      columns: 2,
      columnWidth: 110,
      rowHeight: 60,
    },
  });
  document.getElementById('stencil').appendChild(stencil.value.container);

  // 注册节点形状
  Graph.registerNode('custom-rect', {
    inherit: 'rect',
    width: 80,
    height: 36,
    attrs: { body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' }, text: { fontSize: 12, fill: '#262626' } },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-polygon', {
    inherit: 'polygon',
    width: 80,
    height: 38,
    attrs: { body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' }, text: { fontSize: 12, fill: '#262626' } },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-circle', {
    inherit: 'circle',
    width: 48,
    height: 48,
    attrs: { body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' }, text: { fontSize: 12, fill: '#262626' } },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-cylinder', {
    inherit: 'rect',
    width: 80,
    height: 60,
    markup: [{ tagName: 'ellipse', selector: 'top' }, { tagName: 'path', selector: 'body' }, { tagName: 'text', selector: 'label' }],
    attrs: {
      top: { cx: 40, cy: 10, rx: 40, ry: 10, fill: '#EFF4FF', stroke: '#5F95FF', strokeWidth: 1 },
      body: { d: 'M 0 10 A 40 10 0 0 0 80 10 L 80 50 A 40 10 0 0 1 0 50 Z', fill: '#EFF4FF', stroke: '#5F95FF', strokeWidth: 1 },
      label: { refX: 0.5, refY: 0.5, textAnchor: 'middle', textVerticalAnchor: 'middle', fontSize: 12, fill: '#262626' },
    },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-text', {
    inherit: 'text-block',
    width: 60,
    height: 36,
    attrs: { body: { rx: 4, ry: 4, fill: '#fff', stroke: '#fff' }, text: { fontSize: 12, fill: '#000' } },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-path', {
    inherit: 'path',
    width: 60,
    height: 36,
    attrs: { body: { strokeWidth: 1, stroke: '#5F95FF', fill: '#EFF4FF' }, text: { fontSize: 12, fill: '#262626' } },
    ports: { ...ports.value },
    selectable: true,
  }, true);
  Graph.registerNode('custom-image', {
    inherit: 'rect',
    width: 52,
    height: 52,
    markup: [{ tagName: 'rect', selector: 'body' }, { tagName: 'image' }, { tagName: 'text', selector: 'label' }],
    attrs: {
      body: { strokeWidth: 1, stroke: '#00A4FF', fill: '#00A4FF' },
      image: { width: 26, height: 26, refX: 13, refY: 16 },
      label: { refX: 3, refY: 2, textAnchor: 'left', textVerticalAnchor: 'top', fontSize: 12, fill: '#fff' },
    },
    ports: { ...ports.value },
  }, true);

  // 创建 Stencil 节点
  const r1 = graph.value.createNode({ shape: 'custom-rect', label: '开始', attrs: { body: { rx: 18, ry: 26 } }, selectable: true });
  const r2 = graph.value.createNode({ shape: 'custom-rect', label: '过程', selectable: true });
  const r3 = graph.value.createNode({ shape: 'custom-rect', attrs: { body: { rx: 6, ry: 6 } }, label: '可选过程', selectable: true });
  const r4 = graph.value.createNode({ shape: 'custom-polygon', attrs: { body: { refPoints: '0,10 10,0 20,10 10,20' } }, label: '决策', selectable: true });
  const r5 = graph.value.createNode({ shape: 'custom-polygon', attrs: { body: { refPoints: '10,0 40,0 30,20 0,20' } }, label: '数据', selectable: true });
  const r6 = graph.value.createNode({ shape: 'custom-circle', label: '连接', selectable: true });
  const r7 = graph.value.createNode({ shape: 'custom-cylinder', label: '数据库', selectable: true });
  const r8 = graph.value.createNode({ shape: 'custom-path', label: '文档', attrs: { body: { refD: 'M 0 0 0 4 C 10 8 15 2 25 5 L 25 0 Z' } }, selectable: true });
  const r9 = graph.value.createNode({ shape: 'custom-path', label: '手动输入', attrs: { body: { refD: 'M 0 7 0 15 15 15 15 5 Z' } }, selectable: true });
  const r10 = graph.value.createNode({ shape: 'custom-text', text: '文本' });

  const nodes = [r1, r2, r3, r4, r5, r6, r7, r8, r9, r10];
  for (const node of nodes) {
    await initializeNodeData(node);
  }
  stencil.value.load([r1, r2, r3, r4, r5, r6, r7, r8, r9, r10], 'group1');

  const imageShapes = [
    { label: 'Client', image: 'https://gw.alipayobjects.com/zos/bmw-prod/687b6cb9-4b97-42a6-96d0-34b3099133ac.svg' },
    { label: 'Http', image: 'https://gw.alipayobjects.com/zos/bmw-prod/dc1ced06-417d-466f-927b-b4a4d3265791.svg' },
    { label: 'Api', image: 'https://gw.alipayobjects.com/zos/bmw-prod/c55d7ae1-8d20-4585-bd8f-ca23653a4489.svg' },
    { label: 'Sql', image: 'https://gw.alipayobjects.com/zos/bmw-prod/6eb71764-18ed-4149-b868-53ad1542c405.svg' },
    { label: 'Clound', image: 'https://gw.alipayobjects.com/zos/bmw-prod/c36fe7cb-dc24-4854-aeb5-88d8dc36d52e.svg' },
    { label: 'Mq', image: 'https://gw.alipayobjects.com/zos/bmw-prod/2010ac9f-40e7-49d4-8c4a-4fcf2f83033b.svg' },
  ];
  const imageNodes = imageShapes.map((item) =>
      graph.value.createNode({ shape: 'custom-image', label: item.label, attrs: { image: { 'xlink:href': item.image } }, selectable: true })
  );
  for (const node of imageNodes) {
    await initializeNodeData(node);
  }
  stencil.value.load(imageNodes, 'group2');
};

// 初始化链接桩
const initPorts = () => {
  ports.value = {
    groups: {
      top: { position: 'top', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff', style: { visibility: 'hidden' } } } },
      right: { position: 'right', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff', style: { visibility: 'hidden' } } } },
      bottom: { position: 'bottom', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff', style: { visibility: 'hidden' } } } },
      left: { position: 'left', attrs: { circle: { r: 4, magnet: true, stroke: '#5F95FF', strokeWidth: 1, fill: '#fff', style: { visibility: 'hidden' } } } },
    },
    items: [{ group: 'top' }, { group: 'right' }, { group: 'bottom' }, { group: 'left' }],
  };
};

// 导入 JSON 数据
const importJson = async (jsonData) => {
  graph.value.clearCells();
  const devices = await mockFetchDevices();
  const nodes = jsonData.nodes.map((nodeData) => {
    const node = graph.value.createNode({
      id: nodeData.id,
      shape: nodeData.shape,
      x: nodeData.x,
      y: nodeData.y,
      width: nodeData.width,
      height: nodeData.height,
      attrs: nodeData.attrs,
      ports: { ...ports.value },
      selectable: true,
    });
    const deviceList = devices[nodeData.id] || [];
    node.setData({
      ...jsonData.attribute,
      deviceList,
    });
    return node;
  });

  const edges = jsonData.edges.map((edgeData) => {
    return graph.value.createEdge({
      id: edgeData.id,
      source: edgeData.source,
      target: edgeData.target,
      shape: edgeData.shape,
      attrs: edgeData.attrs,
    });
  });

  graph.value.addCell([...nodes, ...edges]);
  console.log('JSON 导入完成，节点设备列表:', nodes.map((node) => ({ id: node.id, deviceList: node.getData().deviceList })));
};

// 更新 node 数据
const handleNode = (data) => {
  curNode.value = data;
};

// 更新 edge 数据
const handleEdge = (data) => {
  curEdge.value = data;
};

// 收缩配置面板
const handleCollpaseConfig = () => {
  configVisibe.value = false;
  graphRef.value.style.width = 'calc(100% - 250px)';
};

// 展开配置面板
const handleOpenConfig = () => {
  configVisibe.value = true;
  graphRef.value.style.width = `calc(100% - ${configWidth.value + 250}px)`;
};

// 拖拽调整配置面板宽度
const startResize = (e) => {
  e.preventDefault();
  const startX = e.clientX;
  const startWidth = configWidth.value;

  const doResize = (moveEvent) => {
    const dx = startX - moveEvent.clientX;
    let newWidth = startWidth + dx;
    const minWidth = 200;
    const maxWidth = 600;
    newWidth = Math.max(minWidth, Math.min(maxWidth, newWidth));
    configWidth.value = newWidth;
    graphRef.value.style.width = `calc(100% - ${newWidth + 250}px)`;
  };

  const stopResize = () => {
    document.removeEventListener('mousemove', doResize);
    document.removeEventListener('mouseup', stopResize);
  };

  document.addEventListener('mousemove', doResize);
  document.addEventListener('mouseup', stopResize);
};

// 组件挂载时初始化
onMounted(async () => {
  document.addEventListener('keyup', (e) => {
    if (e.keyCode === 27) {
      visible.value = false;
    }
  });
  initGraph();
  graphBindKey();
  graphOnEvent();
  initPorts();
  await initStencil();
  // 默认加载产线 A 的 JSON
  const jsonData = await mockFetchJsonByLineId('lineA');
  await importJson(jsonData);
});
</script>

<style scoped>
.full-screen {
  position: fixed;
  overflow: auto;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: #fff;
  border: 0;
  border-radius: 0px;
  padding: 0;
  margin: 0;
  height: 100%;
}
#container {
  display: flex;
  border: 1px solid #dfe3e8;
  height: 100%;
  width: 100%;
}
#stencil {
  width: 250px;
  height: 100%;
  position: relative;
  border-right: 1px solid #dfe3e8;
}
#graph-container {
  width: calc(100% - 500px);
  height: 100%;
  position: relative;
  pointer-events: auto;
}
#config-container {
  position: relative;
  height: 100%;
  border-left: 1px solid #dfe3e8;
  background: #fff;
}
.resize-bar {
  position: absolute;
  left: -5px;
  top: 0;
  width: 5px;
  height: 100%;
  background: #dfe3e8;
  cursor: col-resize;
  z-index: 10;
}
.resize-bar:hover {
  background: #239edd;
}
.resize-bar:active {
  background: #1a73e8;
}
.collpase-icon {
  position: absolute;
  top: 25px;
  left: -8px;
  color: #aaa;
  background-color: #fff;
  cursor: pointer;
}
.open-icon {
  position: relative;
  top: 10px;
  right: 10px;
  color: #aaa;
  background-color: #fff;
  cursor: pointer;
}
</style>
